﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Channels;
using System.IO;

namespace WcfFlashRemoting.ServiceModel.Channels
{
    class AmfMessageEncoder : MessageEncoder
    {
        MessageVersion version = MessageVersion.None;


        public override string ContentType
        {
            get
            {
                //System.ServiceModel.OperationContext cntxt = System.ServiceModel.OperationContext.Current;
                //if (cntxt != null)
                //{
                //    HttpRequestMessageProperty request = (cntxt.IncomingMessageProperties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty);

                //    if (request != null && request.Headers["Accept"] != null && request.Headers["Accept"].Contains("text/html"))
                //    {
                //        return "text/html";
                //    }
                //}
                return "application/x-amf";
            }
        }

        public override string MediaType
        {
            get { return "application/x-amf"; }
        }

        public override bool IsContentTypeSupported(string contentType)
        {
            if (contentType == "text/html")
            {
                return true;
            }
            bool result = base.IsContentTypeSupported(contentType);
            return result;
        }

        public override MessageVersion MessageVersion
        {
            get { return version; }
        }

        #region Buffers... psh.
        
        public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
        {
            byte[] msgContents = new byte[buffer.Count];
            Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
            bufferManager.ReturnBuffer(buffer.Array);

            using (System.IO.MemoryStream ms = new System.IO.MemoryStream(msgContents))
            {
                return ReadMessage(ms, int.MaxValue, contentType);
            }
        }

        public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
        {
            byte[] messageBytes;
            int messageLength;
            using (MemoryStream ms = new MemoryStream())
            {
                WriteMessage(message, ms);
                ms.Flush();

                messageBytes = ms.GetBuffer();
                messageLength = (int)ms.Position;
            }

            int totalLength = messageLength + messageOffset;
            byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
            Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);

            ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
            return byteArray;
        }

        #endregion

        public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders, string contentType)
        {
            WcfFlashRemoting.IO.AmfReader reader = new WcfFlashRemoting.IO.AmfReader(stream);
            WcfFlashRemoting.AmfObjects.AmfMessage result = reader.ReadAmfMessage();
            var msg = new AmfMultipleMessage(version, result.Headers.ToArray(), result.Body.ToArray(), result.Version);            
            return msg;
        }

        public override void WriteMessage(Message message, Stream stream)
        {
            AmfObjects.AmfMessage msg = new WcfFlashRemoting.AmfObjects.AmfMessage();
            if (message is AmfBaseMessage)
            {
                if (message is AmfMultipleMessage)
                {
                    msg.Body.AddRange((message as AmfMultipleMessage).AmfBodies);
                }
                else if (message is AmfMessage)
                {
                    msg.Body.Add((message as AmfMessage).AmfBody);
                }
                msg.Headers.AddRange((message as AmfBaseMessage).AmfHeaders);
            }
            else 
            {
                StreamWriter sw = new StreamWriter(stream, Encoding.ASCII);
                sw.WriteLine("message must be either 'AmfMessage' or 'AmfMultipleMessage'.<br/>");
                sw.WriteLine(this.GetType().Assembly.FullName);
                sw.Flush();
                if (message.Properties.ContainsKey(HttpResponseMessageProperty.Name))
                {
                    message.Properties.Remove(HttpResponseMessageProperty.Name);
                }
                HttpResponseMessageProperty p = new HttpResponseMessageProperty();
                p.StatusCode = System.Net.HttpStatusCode.OK;
                p.StatusDescription = "OK";
                p.Headers.Add(System.Net.HttpResponseHeader.ContentType, "text/html");
                message.Properties.Add(HttpResponseMessageProperty.Name, p);
                return;
            }
            msg.Version = AmfBaseMessage.GetCurrentAmfVersion;
            WcfFlashRemoting.IO.AmfWriter writer = new WcfFlashRemoting.IO.AmfWriter(stream);
            writer.WriteAmfMessage(msg);
        }
    }
}
